/* 
 * File:   bench.h
 * Author: ljr
 *
 * Created on 03 February 2010, 21:04
 */

#ifndef _BENCH_H
#define	_BENCH_H

#include <cstdlib>
#include <iostream>
#include <vector>

using namespace std;


//#include <pthread.h>
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>

#include <queuing.h>

// mrip2
#include <mrip2.h>
#include <SA/sa_parameter_analyser.h>

// mrip variables
int rank;
int seed_from_master;

enum event_id {
    UNUSED,
    BEGIN_TOUR,
    REQUEST_CONTROLLER,
    FORWARD_UNIT,
    REQUEST_DISK,
    RELEASE_DISK
};

enum raid_levels {
    L0,
    L1,
    L2,
    L3,
    L4,
    L5
};
raid_levels levels[] = {
    L0,
    L1,
    L2,
    L3,
    L4,
    L5
};

enum bunch_of_disks {
    FOUR = 4,
    SIX = 6,
    EIGHT = 8
};
bunch_of_disks disks[] = {
    FOUR,
    SIX,
    EIGHT
};

enum file_sizes {
    SMALL25_BIG75,
    SMALL50_BIG50,
    SMALL75_BIG25
};
file_sizes files[] = {
    SMALL25_BIG75,
    SMALL50_BIG50,
    SMALL75_BIG25
};

enum operation_values {
    WRITE25_READ75,
    WRITE50_READ50,
    WRITE75_READ25
};
operation_values operations[] = {
    WRITE25_READ75,
    WRITE50_READ50,
    WRITE75_READ25
};

// parameters
raid_levels level;
bunch_of_disks number_of_disks;
file_sizes size_of_files;
operation_values io_operations;

const int TIME_LIMIT = 5000000;
Facility* raid_controller = NULL;
vector<Facility*> raid;

// initialization
void parse_arguments(int argc, char **);
void create_facilities();
void initialize_random_engine(long);

// util
unsigned char get_file_size();
unsigned char get_io_operation();

// processing
void begin_tour(void);
void request_controller(void);
void forward_to_unit(void);
void request_disk(void);
void done_end_tour(void);
// process each level
double process_l0(int, unsigned char, int);
double process_l1(int, unsigned char, int);
double process_l2(int, unsigned char, int);
double process_l3(int, unsigned char, int);
double process_l4(int, unsigned char, int);
double process_l5(int, unsigned char, int);
// Array of functions
double (*process_level[6])(int, unsigned char, int) = {
    process_l0,
    process_l1,
    process_l2,
    process_l3,
    process_l4,
    process_l5,
};

// used to make a round robin in order to choose which disk will store the strip
// it will fail when choose 6 disks. Every 86 times, it will skip two.
unsigned char robin = 0;
unsigned long int number_of_interations = 0;
// For demonstration, take a look at this program:
//
//#include <iostream>
//using namespace std;
//int main(int argc, char* argv[]) {
//    unsigned char counter = 0;
//    int x;
//    for (int i = 0; i < 256; i++) {
//        x = counter++;
//        cout << x << ";" << x % 4 << ";" << x % 6 << ";" << x % 8 << endl;
//    }
//    return 0;
//}
//

// Fixed parameters!!
const double MEAN_ARRIVAL_TIME = 3; // How often tokens new requests arrive?
const double FORWARD_OVERHEAD  = 1; // Time get to forward the requesto to the right disk.
//const double WRITING_SPEED     = 0.1225; // Time spend on writing operations.
//const double WRITING_SPEED     = 0.12; // Time spend on writing operations.
const double WRITING_SPEED     = 4; // Time spend on writing operations.
//const double READING_SPEED     = 0.03625;// Time spend on reading operations.
//const double READING_SPEED     = 0.04;// Time spend on reading operations.
const double READING_SPEED     = 1.2;// Time spend on reading operations.

struct token_payload {
    unsigned char unit; // points to the unit that will process the operation
    unsigned char file_size; // size of the file to be processed
    unsigned char io_operation; // I/O operation 0 for writing, 1 for reading
};


// Metrics variables!!
unsigned long int operations_done = 0;
double throughput;

#endif	/* _BENCH_H */

